#!/bin/bash
#
# mk/gist -- build libgist codebase or run libgist driver program
#
# This is a convenience script that obviates the need to switch to the
# cmake out-of-source build directory to build libgist and its driver
# program. If invoked as gist instead of mkgist, this script will run the
# libgist driver program instead of building the libgist codebase.
#
# By default, this script will build the release version of the libgist
# codebase (or, if invoked as gist, launch the release version of the
# libgist driver). Use the -d or --debug option to get it to
# build/launch the debug version. If specified, this option *must* be
# the very first command line argument.
#
# The script will attempt to guess the root directory of the libgist
# codebase by looking for the string "libgist" in the current working
# directory's name. If "libgist" is not found in the current working
# directory, the script expects the path to the libgist root to be passed
# as a command line argument. This *must* be the first argument if not
# using the -d option or the second one if using -d.
#
# Finally, when invoked as mkgist, the script support the use of a -t or
# --run-tests option. If supplied, this *must* be the first argument if
# neither -d nor root directory are used, the second argument if one of
# them is used, or the third command line argument if both -d and root
# directory are specified.
#
# When the -t option is used, mkgist will first build the libgist
# codebase and then run the unit tests.
#
# Remaining command line arguments are passed to the make program as-is
# (or to the libgist driver program if the script is invoked as gist
# instead of mkgist).
#
# The best way to use this script would be to symlink to it in some
# directory that is in your PATH. If you have a personal bin directory in
# your home directory, the following sequence of commands ought to work:
#
#     cd /path/to/libgist
#     ln -s misc/mkgist ~/bin
#     ln -s misc/mkgist ~/bin/gist
#
# Once this is setup, you should be able to use the mkgist command to
# build the libgist codebase and the gist command to run the libgist
# driver program. Just remember to cd somewhere under the libgist
# codebase's root directory before invoking these commands or to supply
# the path to the libgist codebase root if you decided not to use the
# name libgist for the codebase root.
#

#---------------------------- ADMINISTRIVIA -----------------------------

# This file is part of libgist.
#
# libgist is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# libgist is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with libgist; if not, write to the Free Software Foundation, Inc., 59
# Temple Place, Suite 330, Boston, MA 02111-1307 USA.

# REVISION HISTORY
#
# $HeadURL: http://libgist.googlecode.com/svn/branches/wu_dev/misc/mkgist $
# $Id: mkgist 173 2012-03-10 04:44:11Z libgist@gmail.com $

#----------------------- LIBGIST ROOT DIRECTORY -------------------------

# Check if CMakeLists.txt specified in $1 is libgist's top-level build
# file.
#
# NOTE: This function simply looks for a particular string the supplied
# file and, so, is very easy to fool.
function check_cmake_file()
{
    fgrep -q "libgist top-level build file" "$1"
}

# Helper function to try and find the libgist root directory starting at
# the current working directory and moving up from there.
function find_root()
{
    local DIR=`pwd` RET=1
    while true
    do
        # If we're at the filesystem root directory, we couldn't find
        # libgist's root directory; the search ends...
        [ "$DIR" = "/" ] && break

        # See if this directory contains libgist's top-level build file
        if [ -r "$DIR/CMakeLists.txt" ] ; then
           check_cmake_file "$DIR/CMakeLists.txt" && {
               echo "$DIR"
               RET=0
               break
           }
        fi

        # Didn't find the top-level build file yet ==> move up one level
        DIR=`dirname "$DIR"`
    done
    return $RET
}

#-------------------------------- MAIN ----------------------------------

# Restrict executable search path
PATH=/usr/bin:/bin

# Script name for error messages
ME=`basename $0`

# Decide whether we want release or debug builds
BUILD=release # default
[ "$1" = "-d" -o "$1" = "--debug" ] && { BUILD=debug ; shift ; }

# Guess libgist root directory
ROOT=`find_root`
if [ $? -eq 1 ]  # not under libgist? try command line argument
then
   [ -z "$1" ] && {
      echo "$ME: use command line arg to specify libgist root" 1>&2
      exit 1
   }
   ROOT="$1"
   shift

   # Ensure libgist root directory supplied on command line exists and
   # contains top-level build file.
   [ -d "$ROOT" ] || {
       echo "$ME: $ROOT: no such directory" 1>&2
       exit 2
   }
   [ -r "$ROOT/CMakeLists.txt" ] && check_cmake_file "$ROOT/CMakeLists.txt" || {
       echo "$ME: $ROOT: does not contain libgist top-level CMake file" 1>&2
       exit 2
   }
fi

# Looks like we're all set; let's try and either build or run the dang
# thing...
case "$ME" in
   "mkgist")
      cd "$ROOT"
      [ -s build/$BUILD/Makefile ] || {
         rm -rf build/$BUILD
         mkdir -p build/$BUILD
         cd build/$BUILD
         cmake -DCMAKE_BUILD_TYPE=$BUILD ../..
         cd "$ROOT"
      }
      TEST=0
      [ "$1" = "-t" -o "$1" = "--run-tests" ] && { TEST=1 ; shift ; }
      NCPU=`fgrep processor /proc/cpuinfo | wc -l`
      make -j$NCPU -C build/$BUILD $@ && {
         if [ $TEST -eq 1 ] ; then
            exec make -j$NCPU -C build/$BUILD test ARGS=-V
         else
            : # avoid exiting with error code 1 (due to failed test)
         fi
      } ;;

   "gist")
      [ -x "$ROOT"/build/$BUILD/drv/gist ] || {
         echo "$ME: $ROOT/build/$BUILD/drv/gist: no such file" 1>&2
         echo "$ME: please build libgist first using mkgist command" 1>&2
         exit 3
      }
      exec "$ROOT"/build/$BUILD/drv/gist $@ ;;
esac

#------------------------------------------------------------------------

# So things look consistent in everyone's emacs...
# Local Variables:
# indent-tabs-mode: nil
# End:
